// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//
#pragma once

#include <pollux/expression/special_form.h>

namespace kumo::pollux::exec {
    class FieldReference : public SpecialForm {
    public:
        FieldReference(
            TypePtr type,
            const std::vector<ExprPtr> &inputs,
            const std::string &field)
            : SpecialForm(
                  std::move(type),
                  inputs,
                  field,
                  inputs.empty() ? true : false,
                  false /* trackCpuUsage */),
              field_(field) {
        }

        FieldReference(
            TypePtr type,
            const std::vector<ExprPtr> &inputs,
            int32_t index)
            : SpecialForm(
                  std::move(type),
                  inputs,
                  inputs.at(0)->type()->as_row().nameOf(index),
                  false, /* supportsFlatNoNullsFastPath */
                  false /* trackCpuUsage */),
              field_(inputs.at(0)->type()->as_row().nameOf(index)),
              index_(index) {
        }

        const std::string &field() const {
            return field_;
        }

        bool isConstant() const override {
            return SpecialForm::isConstant() && !inputs_.empty();
        }

        int32_t index(const EvalCtx &context) {
            if (index_ != -1) {
                return index_;
            }
            auto *rowType = dynamic_cast<const RowType *>(context.row()->type().get());
            POLLUX_CHECK(rowType, "The context has no row");
            index_ = rowType->getChildIdx(field_);
            return index_;
        }

        void evalSpecialForm(
            const SelectivityVector &rows,
            EvalCtx &context,
            VectorPtr &result) override;

        void evalSpecialFormSimplified(
            const SelectivityVector &rows,
            EvalCtx &context,
            VectorPtr &result) override;

        std::string toString(bool recursive = true) const override;

        std::string toSql(
            std::vector<VectorPtr> *complexConstants = nullptr) const override;

    protected:
        void computeDistinctFields() override;

    private:
        void
        apply(const SelectivityVector &rows, EvalCtx &context, VectorPtr &result);

        const std::string field_;
        int32_t index_ = -1;
    };
} // namespace kumo::pollux::exec
